<!-- 用户管理 -->
<template>
	<div class="app-container">
		<el-row :gutter="20">
			<!-- 部门树 -->
			<el-col :lg="4" :xs="24" class="mb-[12px]">
				<dept-tree v-model="queryParams.deptId" @node-click="handleQuery"/>
			</el-col>

			<!-- 用户列表 -->
			<el-col :lg="20" :xs="24">
				<div class="search-container">
					<el-form ref="queryFormRef" :inline="true" :model="queryParams">
						<el-form-item label="关键字" prop="keywords">
							<el-input
								v-model="queryParams.keywords"
								clearable
								placeholder="用户名/昵称/手机号"
								style="width: 200px"
								@keyup.enter="handleQuery"
							/>
						</el-form-item>

						<el-form-item label="状态" prop="status">
							<el-select
								v-model="queryParams.status"
								class="!w-[100px]"
								clearable
								placeholder="全部"
							>
								<el-option label="启用" value="1"/>
								<el-option label="禁用" value="0"/>
							</el-select>
						</el-form-item>

						<el-form-item label="创建时间">
							<el-date-picker
								v-model="dateTimeRange"
								class="!w-[240px]"
								end-placeholder="截止时间"
								range-separator="~"
								start-placeholder="开始时间"
								type="daterange"
								value-format="YYYY-MM-DD"
							/>
						</el-form-item>

						<el-form-item>
							<el-button type="primary" @click="handleQuery"
							>
								<i-ep-search/>
								搜索
							</el-button
							>
							<el-button @click="handleResetQuery">
								<i-ep-refresh/>
								重置
							</el-button
							>
						</el-form-item>
					</el-form>
				</div>

				<el-card class="table-container" shadow="never">
					<template #header>
						<div class="flex-x-between">
							<div>
								<el-button
									v-hasPerm="['sys:user:add']"
									type="success"
									@click="handleOpenDialog()"
								>
									<i-ep-plus/>
									新增
								</el-button
								>
								<el-button
									v-hasPerm="['sys:user:delete']"
									:disabled="removeIds.length === 0"
									type="danger"
									@click="handleDelete()"
								>
									<i-ep-delete/>
									删除
								</el-button
								>
							</div>
							<div>
								<el-button class="ml-3" @click="handleOpenImportDialog"
								>
									<template #icon>
										<i-ep-upload/>
									</template>
									导入
								</el-button
								>

								<el-button class="ml-3" @click="handleExport"
								>
									<template #icon>
										<i-ep-download/>
									</template>
									导出
								</el-button
								>
							</div>
						</div>
					</template>

					<el-table
						v-loading="loading"
						:data="pageData"
						@selection-change="handleSelectionChange"
					>
						<el-table-column align="center" type="selection" width="50"/>
						<el-table-column
							key="id"
							align="center"
							label="编号"
							prop="id"
							width="100"
						/>
						<el-table-column
							key="username"
							align="center"
							label="用户名"
							prop="username"
						/>
						<el-table-column
							align="center"
							label="用户昵称"
							prop="nickname"
							width="120"
						/>

						<el-table-column
							align="center"
							label="性别"
							prop="genderLabel"
							width="100"
						/>

						<el-table-column
							align="center"
							label="部门"
							prop="deptName"
							width="120"
						/>
						<el-table-column
							align="center"
							label="手机号码"
							prop="mobile"
							width="120"
						/>

						<el-table-column align="center" label="状态" prop="status">
							<template #default="scope">
								<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">{{
										scope.row.status == 1 ? "启用" : "禁用"
									}}
								</el-tag>
							</template>
						</el-table-column>
						<el-table-column
							align="center"
							label="创建时间"
							prop="createTime"
							width="180"
						/>
						<el-table-column fixed="right" label="操作" width="220">
							<template #default="scope">
								<el-button
									v-hasPerm="['sys:user:password:reset']"
									link
									size="small"
									type="primary"
									@click="hancleResetPassword(scope.row)"
								>
									<i-ep-refresh-left/>
									重置密码
								</el-button
								>
								<el-button
									v-hasPerm="['sys:user:edit']"
									link
									size="small"
									type="primary"
									@click="handleOpenDialog(scope.row.id)"
								>
									<i-ep-edit/>
									编辑
								</el-button
								>
								<el-button
									v-hasPerm="['sys:user:delete']"
									link
									size="small"
									type="danger"
									@click="handleDelete(scope.row.id)"
								>
									<i-ep-delete/>
									删除
								</el-button
								>
							</template>
						</el-table-column>
					</el-table>

					<pagination
						v-if="total > 0"
						v-model:limit="queryParams.pageSize"
						v-model:page="queryParams.pageNum"
						v-model:total="total"
						@pagination="handleQuery"
					/>
				</el-card>
			</el-col>
		</el-row>

		<!-- 用户表单弹窗 -->
		<el-drawer
			v-model="dialog.visible"
			:title="dialog.title"
			append-to-body
			@close="handleCloseDialog"
		>
			<!-- 用户新增/编辑表单 -->
			<el-form
				ref="userFormRef"
				:model="formData"
				:rules="rules"
				label-width="80px"
			>
				<el-form-item label="用户名" prop="username">
					<el-input
						v-model="formData.username"
						:readonly="!!formData.id"
						placeholder="请输入用户名"
					/>
				</el-form-item>

				<el-form-item label="用户昵称" prop="nickname">
					<el-input v-model="formData.nickname" placeholder="请输入用户昵称"/>
				</el-form-item>

				<el-form-item label="所属部门" prop="deptId">
					<el-tree-select
						v-model="formData.deptId"
						:data="deptOptions"
						:render-after-expand="false"
						check-strictly
						filterable
						placeholder="请选择所属部门"
					/>
				</el-form-item>

				<el-form-item label="性别" prop="gender">
					<dictionary v-model="formData.gender" code="gender"/>
				</el-form-item>

				<el-form-item label="角色" prop="roleIds">
					<el-select v-model="formData.roleIds" multiple placeholder="请选择">
						<el-option
							v-for="item in roleOptions"
							:key="item.value"
							:label="item.label"
							:value="item.value"
						/>
					</el-select>
				</el-form-item>

				<el-form-item label="手机号码" prop="mobile">
					<el-input
						v-model="formData.mobile"
						maxlength="11"
						placeholder="请输入手机号码"
					/>
				</el-form-item>

				<el-form-item label="邮箱" prop="email">
					<el-input
						v-model="formData.email"
						maxlength="50"
						placeholder="请输入邮箱"
					/>
				</el-form-item>

				<el-form-item label="状态" prop="status">
					<el-radio-group v-model="formData.status">
						<el-radio :label="1">正常</el-radio>
						<el-radio :label="0">禁用</el-radio>
					</el-radio-group>
				</el-form-item>
			</el-form>

			<template #footer>
				<div class="dialog-footer">
					<el-button type="primary" @click="handleSubmit">确 定</el-button>
					<el-button @click="handleCloseDialog">取 消</el-button>
				</div>
			</template>
		</el-drawer>

		<!-- 用户导入弹窗 -->
		<user-import
			v-model:visible="importDialogVisible"
			@import-success="handleOpenImportDialogSuccess"
		/>
	</div>
</template>

<script lang="ts" setup>
defineOptions({
	name: "User",
	inheritAttrs: false,
});

import UserAPI, {UserForm, UserPageQuery, UserPageVO} from "@api/user";
import DeptAPI from "@api/dept";
import RoleAPI from "@api/role";

const queryFormRef = ref(ElForm);
const userFormRef = ref(ElForm);

const loading = ref(false);
const removeIds = ref([]);
const total = ref(0);
const pageData = ref<UserPageVO[]>();
/** 部门下拉选项 */
const deptOptions = ref<OptionType[]>();
/** 角色下拉选项 */
const roleOptions = ref<OptionType[]>();
/** 用户查询参数  */
const queryParams = reactive<UserPageQuery>({
	pageNum: 1,
	pageSize: 10,
});

const dateTimeRange = ref("");
watch(dateTimeRange, (newVal) => {
	if (newVal) {
		queryParams.startTime = newVal[0];
		queryParams.endTime = newVal[1];
	} else {
		queryParams.startTime = undefined;
		queryParams.endTime = undefined;
	}
});

/**  用户弹窗对象  */
const dialog = reactive({
	visible: false,
	title: "",
});

/** 导入弹窗显示状态 */
const importDialogVisible = ref(false);

// 用户表单数据
const formData = reactive<UserForm>({
	status: 1,
});

/** 用户表单校验规则  */
const rules = reactive({
	username: [{required: true, message: "用户名不能为空", trigger: "blur"}],
	nickname: [{required: true, message: "用户昵称不能为空", trigger: "blur"}],
	deptId: [{required: true, message: "所属部门不能为空", trigger: "blur"}],
	roleIds: [{required: true, message: "用户角色不能为空", trigger: "blur"}],
	email: [
		{
			pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
			message: "请输入正确的邮箱地址",
			trigger: "blur",
		},
	],
	mobile: [
		{
			pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
			message: "请输入正确的手机号码",
			trigger: "blur",
		},
	],
});

/** 查询 */
function handleQuery() {
	loading.value = true;
	UserAPI.getPage(queryParams)
		.then((data) => {
			console.log("handleQuery", data);
			pageData.value = data.list;
			total.value = data.total;
		})
		.finally(() => {
			loading.value = false;
		});
}

/** 重置查询 */
function handleResetQuery() {
	queryFormRef.value.resetFields();
	dateTimeRange.value = "";
	queryParams.pageNum = 1;
	queryParams.deptId = undefined;
	queryParams.startTime = undefined;
	queryParams.endTime = undefined;
	handleQuery();
}

/** 行复选框选中记录选中ID集合 */
function handleSelectionChange(selection: any) {
	removeIds.value = selection.map((item: any) => item.id);
}

/** 重置密码 */
function hancleResetPassword(row: { [key: string]: any }) {
	ElMessageBox.prompt(
		"请输入用户「" + row.username + "」的新密码",
		"重置密码",
		{
			confirmButtonText: "确定",
			cancelButtonText: "取消",
		}
	).then(({value}) => {
		if (!value || value.length < 6) {
			// 检查密码是否为空或少于6位
			ElMessage.warning("密码至少需要6位字符，请重新输入");
			return false;
		}
		UserAPI.updatePassword(row.id, value).then(() => {
			ElMessage.success("密码重置成功，新密码是：" + value);
		});
	});
}

/**
 * 打开弹窗
 *
 * @param id 用户ID
 */
async function handleOpenDialog(id?: number) {
	dialog.visible = true;
	// 加载角色下拉数据源
	roleOptions.value = await RoleAPI.getOptions();
	// 加载部门下拉数据源
	deptOptions.value = await DeptAPI.getOptions();

	if (id) {
		dialog.title = "修改用户";
		UserAPI.getFormData(id).then((data) => {
			Object.assign(formData, {...data});
		});
	} else {
		dialog.title = "新增用户";
	}
}

/** 关闭弹窗 */
function handleCloseDialog() {
	dialog.visible = false;
	userFormRef.value.resetFields();
	userFormRef.value.clearValidate();

	formData.id = undefined;
	formData.status = 1;
}

/** 表单提交 */
const handleSubmit = useThrottleFn(() => {
	userFormRef.value.validate((valid: any) => {
		if (valid) {
			const userId = formData.id;
			loading.value = true;
			if (userId) {
				UserAPI.update(userId, formData)
					.then(() => {
						ElMessage.success("修改用户成功");
						handleCloseDialog();
						handleResetQuery();
					})
					.finally(() => (loading.value = false));
			} else {
				UserAPI.add(formData)
					.then(() => {
						ElMessage.success("新增用户成功");
						handleCloseDialog();
						handleResetQuery();
					})
					.finally(() => (loading.value = false));
			}
		}
	});
}, 3000);

/** 删除用户 */
function handleDelete(id?: number) {
	const userIds = [id || removeIds.value].join(",");
	if (!userIds) {
		ElMessage.warning("请勾选删除项");
		return;
	}

	ElMessageBox.confirm("确认删除用户?", "警告", {
		confirmButtonText: "确定",
		cancelButtonText: "取消",
		type: "warning",
	}).then(
		function () {
			loading.value = true;
			UserAPI.deleteByIds(userIds)
				.then(() => {
					ElMessage.success("删除成功");
					handleResetQuery();
				})
				.finally(() => (loading.value = false));
		},
		function () {
			ElMessage.info("已取消删除");
		}
	);
}

/** 打开导入弹窗 */
function handleOpenImportDialog() {
	importDialogVisible.value = true;
}

/** 导入用户成功 */
function handleOpenImportDialogSuccess() {
	handleQuery();
}

/** 导出用户 */
function handleExport() {
	UserAPI.export(queryParams).then((response: any) => {
		const fileData = response.data;
		const fileName = decodeURI(
			response.headers["content-disposition"].split(";")[1].split("=")[1]
		);
		const fileType =
			"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";

		const blob = new Blob([fileData], {type: fileType});
		const downloadUrl = window.URL.createObjectURL(blob);

		const downloadLink = document.createElement("a");
		downloadLink.href = downloadUrl;
		downloadLink.download = fileName;

		document.body.appendChild(downloadLink);
		downloadLink.click();

		document.body.removeChild(downloadLink);
		window.URL.revokeObjectURL(downloadUrl);
	});
}

onMounted(() => {
	handleQuery();
});
</script>
